package cn.xd.core.ddd.diff;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.xd.core.entity.BasicDBEntity;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * @author mirzaLin
 * @data 2023/11/17
 * @description 实体类差异
 **/
@Slf4j
public class EntityDiff extends Diff {
    @Setter
    private Boolean selfModified = false;
    @Setter
    private Boolean selfAdded = false;
    @Setter
    private Boolean selfDeleted = false;

    private final Map<String, Object> fields = new HashMap<>();

    private final Map<String, Object> newFields = new HashMap<>();

    public Object getDiff(String filed) {
        return fields.get(filed);
    }

    public void putDiff(String key, Object diff) {
        fields.put(key, diff);
        if (diff instanceof Diff newDiff) {
            newFields.put(key, newDiff.getNewValue());
        }
    }

    public <T extends BasicDBEntity> T getBean(Class<T> clazz) {
        return BeanUtil.mapToBean(newFields, clazz, true, CopyOptions.create());
    }

    public boolean isEmpty() {
        return fields.isEmpty();
    }

    /**
     * 判断聚合根是否会被修改
     *
     * @return
     */
    public Boolean isSelfModified() {
        return selfModified;
    }

    public Boolean isSelfAdded() {
        return selfAdded;
    }

    public Boolean isSelfDeleted() {
        return selfDeleted;
    }

    private static byte[] serialize(Object object) {
        if (object == null) {
            return null;
        } else {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
            try {
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(object);
                oos.flush();
            } catch (IOException var3) {
                throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), var3);
            }

            return baos.toByteArray();
        }
    }

    private static <T> SerializedLambda getSerializedLambda(SFunction<T, ?> lambda) {
        SerializedLambda serializedLambda = null;
        try {
            ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(serialize(lambda))) {
                @Override
                protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
                    Class<?> clazz = super.resolveClass(objectStreamClass);
                    return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
                }
            };
            serializedLambda = (SerializedLambda) objIn.readObject();
        } catch (Exception x) {
            log.error(x.getMessage());
        }
        return serializedLambda;
    }

    public <T> Object getDiff(SFunction<T, ?> lambda) {
        SerializedLambda serializedLambda = getSerializedLambda(lambda);
        String fieldName = serializedLambda.getImplMethodName().substring("get".length());
        fieldName = fieldName.replaceFirst(fieldName.charAt(0) + "", (fieldName.charAt(0) + "").toLowerCase());
        return fields.get(fieldName);

    }

}
